#include <dirent.h>		//diropen(), dirclose(), readdir()
#include <sys/types.h>	//co-requisite (dir open/close/read), co-requisite (stat)
#include <sys/stat.h>	//stat()
#include <limits.h>		//PATH_MAX
#include <string.h>		//strcmp(), strcpy(), strcat()
#include <stdlib.h>		//realpath(), getenv()
#include <stdio.h>		//fopen(), fclose(), fprintf(), fgets()
#include <errno.h>		//strerror()
#include <unistd.h>		//getcwd()

#include "plib.h"
#include "sllib.h"
#include "gl.h"
#include "db.h"
#include "stag.h"

char* stag_gl_prepare_base_dir(char *path)
	{
	static char newBaseDir[PATH_MAX];
	int len;
	
	realpath(path, newBaseDir);
	
	len=strlen(newBaseDir);
	
	path_build_path(newBaseDir, "", newBaseDir);

	return newBaseDir;
	}

void stag_gl_store_datebase_location(void)
	{
	char path[PATH_MAX];
	FILE *storageFile;
	
	strcpy(path, getenv("HOME"));

	#ifdef STAG_LINUX
	path_build_path(path, STAG_CONFIG_DIR, path);
	#endif

	path_build_path(path, STAG_DATABASE_LOCATION_FILE, path);

	if (!(storageFile=fopen(path, "w")))
		{
		fprintf(stderr, "Error: Could not set default path in file \"%s\". - %s\n", path, strerror(errno));
		}
	else
		{
		if(fprintf(storageFile, "%s\n", stagBaseDir)<0)
			{
			fprintf(stderr, "Error: Could not wrtie to \"%s\"\n", path);
			}
	
		fclose(storageFile);
		fprintf(stderr, "Default system database path set to: \"%s\"\n", stagBaseDir);
		}
	}

char* stag_gl_locate_base_dir(void)
	{
	FILE *tagsDB;
	static char location[PATH_MAX], path[PATH_MAX];
	char *filename=stagDatabase,
		 *filenameHolder=STAG_DATABASE_LOCATION_FILE;
	strcpy(location, ".");
	
	do {
		strcpy(location, path_get_relative_path(location));
		path_build_path(location, filename, path);
				
		if ((tagsDB=fopen(path, "r"))!=NULL)
			{
			fclose(tagsDB);
			stagBaseDir=location;
			return path;
			}
			
		if (strcmp(location, STAG_DIR_SEP)==0)
			{
			break;			
			}
		
		path_build_path(location, "..", location);
		
		} while (1);

	strcpy(path, "");
	strcpy(location, getenv("HOME"));
	path_build_path(location, STAG_CONFIG_DIR, location);
	path_build_path(location, filenameHolder, path);
	
	if (tagsDB=fopen(path, "r"))
		{
		fgets(location, PATH_MAX, tagsDB);
		fclose(tagsDB);
		location[strlen(location)-1]='\0';
		path_build_path(location, filename, path);
		
		if (tagsDB=fopen(path, "r"))
			{
			stagBaseDir=location;
			fclose(tagsDB);
			return path;
			}
		}

	strcpy(path, "");
	strcpy(location, getcwd(NULL, 0));
	path_build_path(location, filename, path);

	stagBaseDir=location;
	return path;
	}

int stag_gl_mod_add(const char *filename, int recurs, int followLink)
	{
	struct stat fileInfo;
	struct dirent *dirInfo;
	DIR *dirHandler;
	char foundFile[PATH_MAX];
	
	#ifdef STAG_LINUX
	if (followLink)
		{
		lstat(filename, &fileInfo);
		}
	else
	#endif
		{
		stat(filename, &fileInfo);
		}
	
	if (!S_ISDIR(fileInfo.st_mode))
		{
		strcpy(foundFile, path_get_relative_path(filename));

		if (foundFile==NULL) return 1;
		
		#ifdef STAG_WINDOWS
		path_flip_slash(foundFile, GL_PATH_FROM_WIN);
		#endif

		stag_db_mod(foundFile);
		}
	else if (recurs==-1)
		{
		return 0;
		}
	else
		{
		if (!(dirHandler=opendir(filename)))
			{
			fprintf(stderr, "Error: Cannot open \"%s\" - %s.\n", 
			path_get_relative_path(filename), strerror(errno));
			return 1;
			}
		
		while ((dirInfo=readdir(dirHandler))!=NULL)
			{
			stat(dirInfo->d_name, &fileInfo);
			path_build_path(filename, dirInfo->d_name, foundFile);
			
			if (S_ISDIR(fileInfo.st_mode))
				{
					if (strcmp(dirInfo->d_name, ".")!=0 &&
						strcmp(dirInfo->d_name, "..")!=0)
					{
					if (path_compare_bases(foundFile))
						{
						if (recurs) //STAG_IS_OPTION(STAG_OPTION_RECURS)
							{
							stag_gl_mod_add(foundFile, 1, followLink);
							}
						else if (recurs==0)
							{
							stag_gl_mod_add(foundFile, -1, followLink);
							}
						}
					}
					
				}
			else
				{
				if (path_compare_bases(foundFile)) stag_gl_mod_add(foundFile, 0, followLink);
				}
			}
			
		closedir(dirHandler);
		}
		
	return 0;
	}

int stag_gl_mod_remove(const char *filename)
	{
	return stag_db_mod(filename);
	}

int stag_gl_mod(const char *filename, int recurs, int followLink)
	{
	if (STAG_IS_OPERATION(STAG_OP_REMOVE)) return stag_gl_mod_remove(filename);
	else return stag_gl_mod_add(filename, recurs, followLink);
	}

int stag_gl_purge(void)
	{
	struct stringlist *pathsInfo;
	char *relPath, absPath[PATH_MAX];
	FILE *fileHandler;
	
	stagOperation=STAG_OP_FIND;
	pathsInfo=stag_db_find(NULL);
	stagTagCount=0; /*memory leak but wont matter*/
	stagTagList=NULL;
	stagOperation=STAG_OP_REMOVE;
	
	while ((relPath=get_next_string_from_stringlist(pathsInfo, 0))!=NULL)
		{
		path_build_path(stagBaseDir, relPath, absPath);

		#ifdef STAG_WINDOWS
		path_flip_slash(absPath, GL_PATH_TO_WIN);
		#endif

		if (!(fileHandler=fopen(absPath, "r"))) //File DNE --> issue removal
			{
			stag_db_mod(relPath);
			#ifdef STAG_WINDOWS
			path_flip_slash(absPath, GL_PATH_FROM_WIN);
			#endif
			
			}
		else //Ignore it
			{
			fclose(fileHandler);
			}
		}
	
	free_stringlist(pathsInfo);
	return 0;
	}
	
void stag_gl_init(void)
	{
	stagBaseDir=stag_gl_prepare_base_dir(stagBaseDir);
	if (STAG_IS_OPTION(STAG_OPTION_DEFAULT_BASE)) stag_gl_store_datebase_location();
	return;
	}

/*******************************************************************************
TODO LIST:
-Fix all static char[] 
-Remove followLink and recurs(?) arguments
-Comment statements
*******************************************************************************/
